// 版权所有2009 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package runtime

import (
	"internal/goarch"
	"runtime/internal/atomic"
	"unsafe"
)

// 定义的常量
const (
	// G状态
	// 
	// 除了指示G的一般状态外，G状态
	// 就像goroutine堆栈上的锁（因此它的
	// 执行用户代码的能力）。
	// 
	// 如果您添加到此列表，请添加到mgcmark中“垃圾回收期间正常”状态的列表
	// 
	// 中。也去吧。
	// 
	// TODO（奥斯汀）：_Gscan钻头的重量可能要轻得多。例如，我们可以选择不运行运行在运行队列中找到的_gscanrunnableabcdefg
	// 直到它们成为_Grunnable。而像
	// \u Gscanwaiting->\u Gscanrunnable这样的转换实际上是可以的，因为
	// /它们不会影响堆栈所有权。

	// u Gidle表示此goroutine刚刚分配，尚未初始化。
	_Gidle = iota // 0 

	// \u Grunnable表示此goroutine在运行队列中。它是
	// 当前未执行用户代码。堆栈不是所有者。
	_Grunnable // 1 

	// \u Grunning意味着此goroutine可以执行用户代码。
	// 堆栈归此goroutine所有。它不在运行队列中。
	// 它被分配了一个M和一个P（g.M和g.M.P是有效的）。
	_Grunning // 2 

	// \u Gsyscall表示此goroutine正在执行系统调用。
	// 它没有执行用户代码。该堆栈归此
	// goroutine所有。它不在运行队列中。它被分配了一个M.
	_Gsyscall // 3 

	// \u Gwaiting意味着该goroutine在运行时被阻止。
	// 它没有执行用户代码。它不在运行队列
	// 中，但应该记录在某个地方（例如，通道等待
	// 队列），以便在必要时准备就绪。堆栈为
	// 非所有*除非*通道操作可以读取或
	// 将堆栈的部分写入相应的通道
	// 锁下。否则，在
	// goroutine进入_Gwaiting（例如，它可能会被移动）后访问堆栈是不安全的。
	_Gwaiting // 4 

	// _Gmoribund_unusedêu当前未使用，但在gdb 
	// 脚本中硬编码。
	_Gmoribund_unused // 5 

	// \u Gdead表示此goroutine当前未使用。它可能是
	// 刚刚退出，在一个自由列表中，或者刚刚初始化。它
	// 未执行用户代码。它可能有也可能没有堆栈
	// 已分配。G及其堆栈（如有）归退出G或从自由
	// 所有。
	// 列表中获得G的M 
	_Gdead // 6 

	// _Genqueue_unused当前未使用。
	_Genqueue_unused // 7 

	// \u Gcopystack表示此goroutine的堆栈正在移动。它
	// 没有执行用户代码，也不在运行队列中。
	// 堆栈归放入_Gcopystack的goroutine所有。
	_Gcopystack // 8 

	// \u Gpreempted意味着此goroutine停止自身以进行
	// /暂停抢占。这就像是在等待，但没有什么能让你为它做好准备。一些suspendG必须CAS 
	// 状态为_gwaitingto承担责任
	// ready（）正在执行此G。
	_Gpreempted // 9 

	// \u Gscan与上述除
	// /\u Grunning之外的状态组合表示GC正在扫描堆栈。
	// goroutine没有执行用户代码，堆栈由设置_Gscan位的goroutine拥有。
	// 
	// \u Gscanrunning不同：它用于短暂阻止
	// 状态转换，而GC向G发送信号，以扫描其自身的
	// 堆栈。这就像_Grunning。
	// 
	// 原子状态&~Gscan提供扫描完成时goroutine将返回的状态
	// 返回。
	_Gscan          = 0x1000
	_Gscanrunnable  = _Gscan + _Grunnable  // 0x1001 
	_Gscanrunning   = _Gscan + _Grunning   // 0x1002 
	_Gscansyscall   = _Gscan + _Gsyscall   // 0x1003 
	_Gscanwaiting   = _Gscan + _Gwaiting   // 0x1004 
	_Gscanpreempted = _Gscan + _Gpreempted // 0x1009 
)

const (
	// P状态

	// Pidle表示没有使用P来运行用户代码或
	// /调度程序。通常，它位于空闲的P列表中，可供调度程序使用，但它可能只是在
	// 其他州。
	// 
	// P由空闲列表或任何
	// 正在转换其状态的对象拥有。它的运行队列为空。
	_Pidle = iota

	// /_Prunning表示P归M所有，用于运行用户代码或调度程序。只有拥有此P 
	// 的M才允许将P的状态从_Prunning更改。M 
	// 可以将P转换为_Pidle（如果它没有更多的工作要做），或_Psyscall（当输入系统调用时），或_Pgcstop（为GC暂停）。M还可以将P 
	// 的所有权直接移交给另一个M（例如，安排一个锁定的g）。
	_Prunning

	// /\u Psyscall表示P没有运行用户代码。它在系统调用中与一个M具有
	// 亲和力，但不属于它，而且
	// 可能会被另一个M窃取。这与_Pidle类似，但
	// 使用轻量级转换并维护M亲和力。
	// 
	// 离开_Psyscall必须通过CAS完成，要么窃取
	// 要么重新获取P。注意，这有ABA的危险：即使
	// 一个M在系统调用后成功地将其原始P恢复到_删减
	// 它必须理解P可能已经被另一个M在过渡期间使用。
	_Psyscall

	// /_Pgcstop意味着一个P被STW暂停，并由阻止世界的M 
	// /拥有。阻止了世界
	// 的M继续使用其P，即使在_Pgcstop中。将
	// 从_Prunning转换为_Pgcstop会导致M释放其P和
	// park。
	// 
	// P将保留其运行队列，并且startTheWorld将重新启动
	// Ps上具有非空运行队列的调度程序。
	_Pgcstop

	// /\u Pdead表示不再使用P（GOMAXPROCS收缩）。我们
	// 如果GOMAXPROCS增加，我们将重复使用Ps。死掉的P主要是
	// 被剥夺了资源，尽管有一些东西仍然是
	// （例如，跟踪缓冲区）。
	_Pdead
)

// 互斥锁。在无争用的情况下，
// 与自旋锁（只有几个用户级指令）一样快，
// 但在争用路径上，它们睡在内核中。
// 已调零的互斥锁已解锁（无需初始化每个锁）。
// 初始化有助于静态锁排序，但不是必需的。
type mutex struct {
	// 如果锁排名被禁用，则为空结构，否则包括锁排名
	lockRankStruct
	// 基于Futex的impl将其视为uint32密钥，
	// 而基于sema的impl将其视为M*waitm。
	// 过去是一个工会，但工会破坏了它。
	key uintptr
}

// 在一次性事件中睡眠和醒来。
// 在调用notesleep或notewakeup之前，
// 必须调用noteclear来初始化便笺。
// 那么，只有一个线程可以调用notesleep 
// 并且只有一个线程可以调用notewakeup（一次）。
// 调用notewakeup后，notesleep 
// 将返回。未来的睡眠将立即恢复。
// 只有在
// 返回上一个notesleep后才能调用后续noteclear，例如，不允许
// 在NoteWake之后直接调用noteclear。
// 
// notetsleep类似于notesleep，但在
// 给定的纳秒数后醒来，即使
// 事件尚未发生。如果一个goroutine使用NotesLeep来
// 早起，它必须等待调用noteclear，直到它
// 可以确定没有其他goroutine正在调用
// notewakeup。
// 
// notesleep/notetsleep通常在g0上调用，
// notetsleep类似于notetsleep，但在用户g上调用。
type note struct {
	// Futex-based impl将其视为uint32键，
	// ，而基于语义的impl则视为M*waitm。
	// 过去是一个工会，但工会破裂了。
	key uintptr
}

type funcval struct {
	fn uintptr
	// 可变大小，fn特定数据此处
}

type iface struct {
	tab  *itab
	data unsafe.Pointer
}

type eface struct {
	_type *_type
	data  unsafe.Pointer
}

func efaceOf(ep *any) *eface {
	return (*eface)(unsafe.Pointer(ep))
}

// Guintpr、muintptr和puintptr都用于绕过写屏障。
// 当当前P已释放
// 时，避免写入障碍尤其重要，因为GC认为世界已停止，而
// 意外写入障碍将不会与GC同步，
// 这可能会导致一个半执行的写屏障，它标记了对象
// 但没有将其排队。如果GC跳过该对象并在
// 队列出现之前完成，它将错误地释放该对象。
// 
// 我们尝试使用特殊的赋值函数，仅在不使用
// 保持运行的P时调用，但随后对特定内存
// word的一些更新遇到写入障碍，而有些没有。这打破了
// 写屏障阴影检查模式，而且也很可怕：让
// 一个被GC完全忽略的单词比让
// 只忽略几个更新要好。
// 
// Gs和Ps始终可以通过
// allgs和allp列表中的真指针访问，或者（在到达这些列表之前的分配过程中）
// 从堆栈变量访问。
// 
// Ms始终可以通过allm或
// freem的真指针访问。与Gs和Ps不同，我们提供免费Ms，因此
// 任何东西都不能在安全点上持有muintptr，这一点很重要。

// 一个guintpttr拥有一个goroutine指针，但输入为uintptpr 
// 以绕过写障碍。它用于Gobuf goroutine状态
// 以及在没有P.
// 
// Gobuf操作的调度列表中。g goroutine指针几乎总是由汇编代码更新。
// 在为数不多的几个地方之一，它是由Go代码更新的-func save-它必须是
// 被视为uintptr，以避免在不好的时间发出写屏障。
// 我们将字段的类型更改为uintptpr，
// 程序集操作中缺少的写屏障。
// 以完全不需要写屏障，而不是找出如何发出
// 
// Goroutine结构在allg列表中发布，从未释放。
// 这将阻止收集goroutine结构。
// 从来没有一个时间是这样的。g中只包含对goroutine的引用：在allg中发布goroutine是第一位的。
// Goroutine指针也保存在不可见的地方，比如TLS、
// 所以我看不到它们一直在移动。如果我们真的想在GC中开始移动数据
// 的话，我们需要从
// 备用竞技场分配goroutine结构。使用guintptr并不会让问题变得更糟。
// 请注意。伯格，波尔德斯。wg还以uintptr形式存储g，
// 因此，如果g开始移动，它们也需要更新。
type guintptr uintptr

// go:nosplit 
func (gp guintptr) ptr() *g { return (*g)(unsafe.Pointer(gp)) }

// go:nosplit 
func (gp *guintptr) set(g *g) { *gp = guintptr(unsafe.Pointer(g)) }

// go:nosplit 
func (gp *guintptr) cas(old, new guintptr) bool {
	return atomic.Casuintptr((*uintptr)(unsafe.Pointer(gp)), uintptr(old), uintptr(new))
}

// setGNoWB执行*gp=new，无写入障碍。
// 适用于无法使用guintptr的情况。
// go:nosplit 
// go:nowritebarrier 
func setGNoWB(gp **g, new *g) {
	(*guintptr)(unsafe.Pointer(gp)).set(new)
}

type puintptr uintptr

// go:nosplit 
func (pp puintptr) ptr() *p { return (*p)(unsafe.Pointer(pp)) }

// go:nosplit 
func (pp *puintptr) set(p *p) { *pp = puintptr(unsafe.Pointer(p)) }

// muintptr是垃圾收集器不跟踪的一个*m。
// 
// 因为我们提供免费Ms，所以对
// muintptrs有一些额外的限制：
// 
// 1。切勿在安全点附近持有muintptr。
// 
// 2。堆中的任何muintptr都必须由M本身拥有，这样它就可以
// 确保在最后一个true*M被释放时它没有被使用。
type muintptr uintptr

// go:nosplit 
func (mp muintptr) ptr() *m { return (*m)(unsafe.Pointer(mp)) }

// go:nosplit 
func (mp *muintptr) set(m *m) { *mp = muintptr(unsafe.Pointer(m)) }

// setMNoWB执行*mp=new，无写障碍。
// 适用于无法使用muintptr的情况。
// go:nosplit 
// go:nowritebarrier 
func setMNoWB(mp **m, new *m) {
	(*muintptr)(unsafe.Pointer(mp)).set(new)
}

type gobuf struct {
	// libmach已知sp、pc和g的偏移量（硬编码）。
	// 
	// ctxt对于GC来说是不寻常的：它可能是一个
	// 堆分配函数，所以GC需要跟踪它，但它
	// 需要设置并从汇编中清除，在汇编中
	// 很难设置写障碍。然而，ctxt实际上是一个
	// 保存的实时寄存器，我们只在
	// 真实寄存器和gobuf之间交换它。因此，在堆栈扫描期间，我们将其视为
	// 根，这意味着保存
	// 并恢复它的程序集不需要写屏障。它仍然是
	// 作为指针键入的，以便Go的任何其他写入操作都可以获得
	// 写入障碍。
	sp   uintptr
	pc   uintptr
	g    guintptr
	ctxt unsafe.Pointer
	ret  uintptr
	lr   uintptr
	bp   uintptr // 对于支持帧指针的体系结构
}

// sudog表示等待列表中的g，例如用于在通道上发送/接收
// 的g。
// 
// sudog是必需的，因为↔ 同步对象关系
// 是多对多。g可能在许多等待列表中，因此可能存在
// 一个g有很多SUDOG；而且许多G可能正在等待同一个
// 同步对象，因此一个对象可能有多个sudog。
// 
// sudogs是从一个特殊的池中分配的。使用acquireSudog和
// 释放Sudog来分配和释放它们。
type sudog struct {
	// 以下字段受hchan保护。锁定
	// 此sudog正在阻塞的通道。shrinkstack依赖于
	// 这适用于参与频道运营的sudogs。

	g *g

	next *sudog
	prev *sudog
	elem unsafe.Pointer // 数据元素（可能指向堆栈）

	// 以下字段永远不会同时访问。
	// 对于通道，waitlink仅由g访问。
	// 对于信号量，所有字段（包括上面的字段）
	// 仅在持有信号根锁时访问。

	acquiretime int64
	releasetime int64
	ticket      uint32

	// isSelect表示g正在参加一个select，因此
	// g.selectDone必须在唤醒比赛中获胜。
	isSelect bool

	// 成功表示通过c频道的通信是否成功。如果goroutine被唤醒是因为通过通道c传递了
	// 值，则为真；如果被唤醒是因为c被关闭，则为假。
	success bool

	parent   *sudog // semaRoot二叉树
	waitlink *sudog // g.等待列表或semaRoot 
	waittail *sudog // semaRoot 
	c        *hchan // channel 
}

type libcall struct {
	fn   uintptr
	n    uintptr // 参数数
	args uintptr // 参数
	r1   uintptr // 返回值
	r2   uintptr
	err  uintptr // 错误数
}

// 堆栈描述Go执行堆栈。
// 堆栈的边界正好是[lo，hi]，
// 两侧没有隐式数据结构。
type stack struct {
	lo uintptr
	hi uintptr
}

// heldLockInfo给出了关于持有锁的信息和锁的等级
type heldLockInfo struct {
	lockAddr uintptr
	rank     lockRank
}

type g struct {
	// 堆栈参数。
	// 堆栈描述了实际的堆栈内存：[stack.lo，stack.hi]
	// stackguard0是在Go stack growth序言中比较的堆栈指针。
	// 它通常是stack.lo+StackGuard，但可以通过StackPrempt触发抢占。
	// stackguard1是在C stack growth序言中比较的堆栈指针。
	// 它是在g0和gsignal堆栈上的stack.lo+StackGuard。
	// 在其他goroutine堆栈上为~0，以触发对morestackc的调用（并崩溃）。
	stack       stack   // 运行时已知偏移量/cgo 
	stackguard0 uintptr // liblink 
	stackguard1 uintptr // liblink已知偏移量

	_panic    *_panic // 最里面的恐慌-liblink已知偏移量
	_defer    *_defer // 最里面的延迟
	m         *m      // 当前m；arm liblink 
	sched     gobuf
	syscallsp uintptr // 如果状态==Gsyscall，syscallsp=sched，则偏移量已知。gc期间要使用的sp 
	syscallpc uintptr // 如果状态==Gsyscall，syscallpc=sched。在gc期间使用的pc 
	stktopsp  uintptr // 堆栈顶部的预期sp，用于检查回溯
	// 参数是一个通用指针参数字段，用于在特定上下文中传递
	// 值，在这些特定上下文中，很难找到
	// 参数的其他存储。目前有三种使用方式：
	// 1。当通道操作唤醒阻塞的goroutine时，它将param设置为
	// 指向已完成阻塞操作的sudog。
	// 2。通过gcAssistAlloc1向调用者发回信号，表示goroutine完成了
	// GC循环。以任何其他方式这样做都是不安全的，因为goroutine的
	// 堆栈可能同时移动了。
	// 3。因为禁止在运行时分配
	// 闭包，所以通过debugCallWrap将参数传递给新的goroutine。
	param        unsafe.Pointer
	atomicstatus uint32
	stackLock    uint32 // sigprof/scang lock；TODO:折叠到原子状态
	goid         int64
	schedlink    guintptr
	waitsince    int64      // 大约g被阻塞的时间
	waitreason   waitReason // 如果状态==g等待

	preempt       bool // 抢占信号，复制stackguard0=stackpreempt 
	preemptStop   bool // 转换到_gpreemptedon preemption；否则，只需重新调度
	preemptShrink bool // 在同步安全点收缩堆栈

	// 如果g在异步
	// 安全点停止，则设置异步安全点。这意味着堆栈
	// 上存在没有精确指针信息的帧。
	asyncSafePoint bool

	paniconfault bool // 意外故障地址上的恐慌（而不是崩溃）
	gcscandone   bool // g已扫描堆栈；受状态为
	throwsplit   bool // 的Gscan位保护不能拆分堆栈
	// activeStackChans表示有解锁的通道
	// 指向此goroutine的堆栈。如果为true，则堆栈
	// 复制需要获取通道锁，以保护堆栈中的这些
	// 区域。
	activeStackChans bool
	// parkingOnChan表示goroutine即将放弃
	// 。它是一个布尔值，但会自动更新。
	parkingOnChan uint8

	raceignore     int8     // 忽略种族检测事件
	sysblocktraced bool     // StartTrace已发出有关此goroutine的EVGOINSCALL 
	tracking       bool     // 我们是否跟踪此G以获取sched延迟统计
	trackingSeq    uint8    // 用于决定是否跟踪此G 
	runnableStamp  int64    // G上次可运行的时间戳，仅用于跟踪
	runnableTime   int64    // 运行时所花费的时间，运行时清除，仅用于跟踪
	sysexitticks   int64    // cputicks when syscall已返回（用于跟踪）
	traceseq       uint64   // trace event sequencer 
	tracelastp     puintptr // last P为此goroutine发出事件
	lockedm        muintptr
	sig            uint32
	writebuf       []byte
	sigcode0       uintptr
	sigcode1       uintptr
	sigpc          uintptr
	gopc           uintptr         // pc of go语句创建了此goroutine 
	ancestors      *[]ancestorInfo // 
	startpc        uintptr         // goroutine函数的pc 
	racectx        uintptr
	waiting        *sudog         // sudog正在等待的结构（具有有效的元素ptr）；锁顺序
	cgoCtxt        []uintptr      // cgo回溯上下文
	labels         unsafe.Pointer // 探查器标签
	timer          *timer         // 缓存时间计时器。Sleep 
	selectDone     uint32         // 我们正在参加一场精选赛，有人赢了吗？

	// Per-G GC state 

	// gcAssistBytes就分配的
	// 字节而言，这是G的GC辅助学分。如果这是肯定的，则G有权在没有协助的情况下分配gcAssistBytes字节。如果此
	// 为负值，则G必须通过执行
	// 扫描工作来纠正此错误。我们以字节为单位进行跟踪，以便快速更新
	// 并检查malloc热路径中的债务。辅助比率
	// 决定了它与扫描工作债务的对应关系。
	gcAssistBytes int64
}

// gTrackingPeriod是两次
// 延迟跟踪运行之间的_Grunning转换数。
const gTrackingPeriod = 8

const (
	// tlsSlots是在某些平台上为TLS保留的指针大小的插槽数，如Windows。
	tlsSlots = 6
	tlsSize  = tlsSlots * goarch.PtrSize
)

type m struct {
	g0      *g     // goroutine with scheduling stack 
	morebuf gobuf  // gobuf arg to morestack 
	divmod  uint32 // div/mod arm分母-liblink已知

	// 调试器未知字段。
	procid        uint64            // 对于调试器，但偏移量非硬编码
	gsignal       *g                // 信号处理g 
	goSigStack    gsignalStack      // Go分配的信号处理堆栈
	sigmask       sigset            // 保存的信号掩码的存储
	tls           [tlsSlots]uintptr // 线程本地存储（用于x86外部寄存器）
	mstartfn      func()
	curg          *g       // 当前运行的GOROUTE 
	caughtsig     guintptr // GOROUTE在致命信号
	p             puintptr // 附加的p用于执行go代码（如果不执行go代码，则为零）
	nextp         puintptr
	oldp          puintptr // 执行系统调用之前附加的p 
	id            int64
	mallocing     int32
	throwing      int32
	preemptoff    string // 如果！=“”，保持curg在这个m上运行
	locks         int32
	dying         int32
	profilehz     int32
	spinning      bool // m没有工作，正在积极寻找工作
	blocked       bool // m被阻止在一个便笺
	newSigstack   bool // minit在名为sigaltstack 
	printlock     int8
	incgo         bool   // m的C线程上执行cgo调用
	freeWait      uint32 // if==0，可以安全地释放g0并删除m（原子）
	fastrand      uint64
	needextram    bool
	traceback     uint8
	ncgocall      uint64      // cgo调用总数
	ncgo          int32       // 当前正在进行的cgo调用数
	cgoCallersUse uint32      // 如果非零，则临时使用的cgo调用
	cgoCallers    *cgoCallers // cgo回溯如果cgo崩溃，则调用
	park          note
	alllink       *m // 在创建此线程的所有m 
	schedlink     muintptr
	lockedg       guintptr
	createstack   [32]uintptr // 堆栈上。
	lockedExt     uint32      // 外部锁线程的跟踪
	lockedInt     uint32      // 内部锁线程的跟踪
	nextwaitm     muintptr    // 下一个m正在等待sched上的锁
	waitunlockf   func(*g, unsafe.Pointer) bool
	waitlock      unsafe.Pointer
	waittraceev   byte
	waittraceskip int
	startingtrace bool
	syscalltick   uint32
	freelink      *m // 。freem 

	// 之所以出现这些函数，是因为它们太大，无法放在低级别NOSPLIT函数的堆栈
	// 上。
	libcall   libcall
	libcallpc uintptr // 对于cpu探查器
	libcallsp uintptr
	libcallg  guintptr
	syscall   libcall // 在windows上存储系统调用参数

	vdsoSP uintptr // 在VDSO调用时用于回溯的SP（如果不在调用中，则为0）
	vdsoPC uintptr // 在VDSO调用时用于回溯的PC 

	// 抢占根统计完成的抢占
	// 信号数。这用于检测何时请求抢占
	// 但失败。原子级访问。
	preemptGen uint32

	// 这是否是此M上挂起的抢占信号。
	// 以原子方式访问。
	signalPending uint32

	dlogPerM

	mOS

	// 此m最多持有10个锁，由锁排序代码维护。
	locksHeldLen int
	locksHeld    [10]heldLockInfo
}

type p struct {
	id          int32
	status      uint32 // 皮德尔/修剪/之一。。。
	link        puintptr
	schedtick   uint32     // 在每次调度程序调用时递增
	syscalltick uint32     // 在每次系统调用时递增
	sysmontick  sysmontick // 系统监视到的最后一个勾号
	m           muintptr   // 返回到相关m（如果空闲则为零）
	mcache      *mcache
	pcache      pageCache
	raceprocctx uintptr

	deferpool    []*_defer // 可用的延迟结构池（参见panic.go）
	deferpoolbuf [32]*_defer

	// goroutine ID的缓存，摊销对runtime·sched的访问。戈伊金。
	goidcache    uint64
	goidcacheend uint64

	// 可运行goroutine的队列。无锁访问。
	runqhead uint32
	runqtail uint32
	runq     [256]guintptr
	// runnext，如果非零，则是由
	// 当前G准备好的可运行G，应该下一步运行，而不是
	// 如果运行G的时间还有时间，则运行Q 
	// 切片。它将继承当前时间
	// 切片中剩余的时间。如果一组goroutines被锁定在
	// 通信和等待模式中，这将调度设置为
	// 单元的goroutines，并消除（可能较大的）调度
	// 延迟，否则，将准备好的
	// goroutines添加到运行队列的末尾会导致延迟。
	// 
	// 请注意，虽然其他P可能会自动将其归零，但
	// 只有所有者P可以将其归零为有效的G。
	runnext guintptr

	// 可用的G（status==Gdead）
	gFree struct {
		gList
		n int32
	}

	sudogcache []*sudog
	sudogbuf   [128]*sudog

	// 堆中mspan对象的缓存。
	mspancache struct {
		// 我们需要一个显式的长度，因为这个字段在不允许写障碍的分配代码路径中使用，
		// 并且消除写障碍/保持它从
		// 切片更新中消除是很棘手的，不仅仅是管理长度
		// 我们自己。
		len int
		buf [128]*mspan
	}

	tracebuf traceBufPtr

	// traceSweep表示应该跟踪扫描事件。
	// 用于延迟扫描开始事件，直到实际扫描完跨度
	// 为止。
	traceSweep bool
	// traceSwept和tracerclaimmed跟踪当前扫描循环中通过扫描扫描扫描和回收的字节数。
	traceSwept, traceReclaimed uintptr

	palloc persistentAlloc // per-P避免互斥

	_ uint32 // 

	// 计时器堆上第一个条目的when字段下面的原子字段对齐。
	// 这是使用原子函数更新的。
	// 如果计时器堆为空，则为0。
	timer0When uint64

	// 已知的最早的计时器下一个时间字段，具有
	// TIMERMODIEDEARLYER状态。由于计时器可能已被
	// 再次修改，因此不需要任何具有此值的计时器。
	// 这是使用原子函数更新的。
	// 如果没有时间修改的早期计时器，则为0。
	timerModifiedEarliest uint64

	// Per-P GC状态
	gcAssistTime         int64 // ASISTALLOC中的纳秒
	gcFractionalMarkTime int64 // 分数标记工作程序（原子）中的纳秒

	// gcMarkWorkerMode是下一个标记工作程序运行的模式。
	// 也就是说，它用于与工作程序goroutine 
	// 进行通信，由
	// gcController选择立即执行。Findrunnablegworker。在安排其他goroutine时，
	// 此字段必须设置为gcMarkWorkerNotWorker。
	gcMarkWorkerMode gcMarkWorkerMode
	// gcMarkWorkerStartTime是最新的
	// mark worker启动的nanotime（）。
	gcMarkWorkerStartTime int64

	// gcw是P的GC工作缓冲缓存。工作缓冲区是
	// 由写屏障填充，由mutator assists耗尽，
	// 在某些GC状态转换上处理。
	gcw gcWork

	// wbBuf是这个P的GC写屏障缓冲区。ABCFDG 
	wbBuf wbBuf


	// statsSeq是一个计数器，指示此P当前是否正在写入任何统计数据。它的价值是偶数而非偶数，奇数而非偶数。
	statsSeq uint32

	// 定时器锁。我们通常在这个P上运行
	// 时访问计时器，但调度程序也可以在另一个P上执行。
	timersLock mutex

	// 在某个时间要执行的操作。这用于实现
	// 标准库的时间包。
	// 必须持有timersLock才能访问。
	timers []*timer

	// P堆中的计时器数。
	// 使用原子指令修改。
	numTimers uint32

	// P堆中已删除计时器的数量。
	// 使用原子指令修改。
	deletedTimers uint32

	// 执行计时器函数时使用的竞争上下文。
	timerRaceCtx uintptr

	// scannableStackSizeDelta累积由
	// live goroutines（即符合堆栈扫描条件的）所持有的堆栈空间量。
	// 已刷新到gcController。scannableStackSizeSlack 
	// 或达到-scannableStackSizeSlack后的scannableStackSize。
	scannableStackSizeDelta int64

	// preempt设置为指示此P应尽快进入
	// 调度程序（无论G在其上运行什么）。
	preempt bool

	// 不再需要填充。错误共享现在不成问题，因为p足够大，它的大小类是缓存线大小的整数倍（对于我们的任何体系结构）。
}

type schedt struct {
	// 以原子方式访问。保持在顶部，以确保在32位系统上对齐。
	goidgen   uint64
	lastpoll  uint64 // 最后一次网络轮询的时间，如果当前正在轮询
	pollUntil uint64 // 当前轮询睡眠的时间

	lock mutex

	// 当增加nmidle、NMIDELOCKED、nmsys或nmfreed时，请确保调用checkdead（）。

	midle        muintptr // 空闲m等待工作
	nmidle       int32    // 空闲m等待工作
	nmidlelocked int32    // 锁定m等待工作
	mnext        int64    // 已创建和下一个m ID 
	maxmcount    int32    // 允许的最大m数
	nmsys        int32    // 系统m未计入死锁

	ngsys uint32 // 系统goroutine的累积数量；更新了原子级

	pidle      puintptr // idle p的
	npidle     uint32
	nmspinning uint32 // 请参阅进程中的“工作线程停止/取消连接”注释。去

	// 全局可运行队列。
	runq     gQueue
	runqsize int32

	// 禁用控件选择性禁用调度程序。
	// 
	// 使用schedEnableUser控制此操作。
	// 
	// 禁用受sched保护。锁
	disable struct {
		// 用户禁用用户goroutine的调度。
		user     bool
		runnable gQueue // pending runnable Gs 
		n        int32  // runnable 
	}

	// Global cache of dead G's.
	gFree struct {
		lock    mutex
		stack   gList // Gs with stacks 
		noStack gList // Gs with stacks 
		n       int32
	}

	// sudog structs的中央缓存。
	sudoglock  mutex
	sudogcache *sudog

	// 可用延迟结构的中央池。
	deferlock mutex
	deferpool *_defer

	// freem是设置了
	// m.exited后等待释放的m的列表。通过m.freelink链接。
	freem *m

	gcwaiting  uint32 // gc正在等待运行
	stopwait   int32
	stopnote   note
	sysmonwait uint32
	sysmonnote note

	// safepointFn应该在下一个gc的每个P上调用
	// safepoint如果设置了P.RUNSAFEPINTFN。
	safePointFn   func(*p)
	safePointWait int32
	safePointNote note

	profilehz int32 // cpu配置文件率

	procresizetime int64 // /nanotime（）对gomaxprocs的上次更改
	totaltime      int64 // ∫gomaxprocs dt to procresizetime 

	// sysmonlock在运行时保护sysmon的操作。
	// 
	// 获取并保持此互斥锁，以阻止sysmon与运行时的其余部分交互。
	sysmonlock mutex

	// timeToRun是调度延迟的分布，定义为
	// 在
	// 转换为_Grunning之前，G处于_Grunnable状态的时间总和。
	// 
	// timeToRun受sched保护。锁
	timeToRun timeHistogram
}

// SIGTAB的标志字段的值。
const (
	_SigNotify   = 1 << iota // let信号。通知有信号，即使来自内核
	_SigKill                 // if信号。Notify不接受，悄悄退出
	_SigThrow                // if信号。Notify不接收信号，大声退出
	_SigPanic                // 如果信号来自内核，则惊慌
	_SigDefault              // 如果没有明确请求信号，则不要监视它
	_SigGoExit               // 导致所有运行时进程退出（仅用于计划9）。
	_SigSetStack             // 不显式安装处理程序，但将SA_ONSTACK添加到现有的libc处理程序
	_SigUnblock              // 始终取消阻止；参见blockableSig 
	_SigIgn                  // /_SIG_DFL操作是忽略信号
)

// 内存中每个函数的布局由链接器
// 参见https:
// 与链接器（../cmd/link/internal/ld/pcln.go:/pclntab）保持同步
// 与包调试/gosym和symtab保持同步。进入包运行时。
type _func struct {
	entryoff uint32 // 启动pc，作为模块数据的偏移量。文本/pcHeader。textStart 
	nameoff  int32  // 函数名

	args        int32  // 输入/输出参数大小
	deferreturn uint32 // 延迟返回调用指令从条目开始的偏移量（如果有）。

	pcsp      uint32
	pcfile    uint32
	pcln      uint32
	npcdata   uint32
	cuOffset  uint32 // 运行时。此函数的CU 
	funcID    funcID // 为某些特殊运行时函数
	flag      funcFlag
	_         [1]byte // pad 
	nfuncdata uint8   // 设置的cutab偏移量必须是最后一个，必须在uint32对齐的边界
}

// 伪函数上结束，该伪函数针对内联代码中出现的PC返回。
// A*Func可以是A*u Func或A*funcinl，它们由第一个UINTPTTR区分为
// 。
type funcinl struct {
	ones  uint32  // 设置为^0以区别于_func
	entry uintptr // 实际（最外层）帧的输入
	name  string
	file  string
	line  int
}

// 编译器已知的Itab布局
// 分配在非垃圾收集内存
// 需要与
// cmd/compile/internal/reflectdata/reflect。开始：/^func。写塔布斯。
type itab struct {
	inter *interfacetype
	_type *_type
	hash  uint32 // 复制_类型。搞砸用于类型开关。
	_     [4]byte
	fun   [1]uintptr // 可变大小。fun[0]==0表示_type不实现inter。
}

// 无锁堆栈节点。
// 也被称为出口测试。去
type lfnode struct {
	next    uint64
	pushcnt uintptr
}

type forcegcstate struct {
	lock mutex
	g    *g
	idle uint32
}

// extendRandom将r[：n]中的随机数扩展到整个切片r。
// 将n<0视为n==0。
func extendRandom(r []byte, n int) {
	if n < 0 {
		n = 0
	}
	for n < len(r) {
		// 使用哈希函数和时间种子扩展随机位。
		w := n
		if w > 16 {
			w = 16
		}
		h := memhash(unsafe.Pointer(&r[n-w]), uintptr(nanotime()), uintptr(w))
		for i := 0; i < goarch.PtrSize && n < len(r); i++ {
			r[n] = byte(h)
			n++
			h >>= 8
		}
	}
}

// 如果在此处添加字段，请添加代码以在堆栈中清除该字段。
// 此结构必须与cmd/compile/internal/ssagen/ssa中的代码匹配。go:deferstruct 
// 和cmd/compile/internal/ssagen/ssa。去：（*州）。呼叫
// 将在堆栈上分配一些延迟，在堆上分配一些延迟。
// 所有延迟在逻辑上都是堆栈的一部分，因此不需要为
// 初始化它们。所有延迟必须手动扫描，
// 对于堆延迟，标记。
type _defer struct {
	started bool
	heap    bool
	// openDefer表示此_defer用于带有开放编码
	// defers的帧。对于整个帧，我们只有一个延迟记录（这可能是
	// 当前有0个、1个或多个延迟处于活动状态）。
	openDefer bool
	sp        uintptr // 延迟时的sp 
	pc        uintptr // 延迟时的pc 
	fn        func()  // 对于开放编码延迟
	_panic    *_panic // 正在运行延迟
	link      *_defer // 下一个延迟

	// 如果openDefer为true，下面的字段将记录有关堆栈的值
	// 帧和具有开放编码延迟的关联函数。sp 
	// 以上将是帧的sp，pc将是函数中
	// 延迟返回调用的地址。
	fd   unsafe.Pointer // funcdata用于与帧关联的函数
	varp uintptr        // varp值用于堆栈帧
	// framepc是与堆栈帧关联的当前pc。
	// 加上上面的sp（与堆栈帧关联的sp），
	// framepc/sp可以用作pc/sp对，通过
	// gentraceback（）继续堆栈跟踪。
	framepc uintptr
}

// A _panic保存关于活跃恐慌的信息。
// 
// A _panic值只能存在于堆栈上。
// 
// argp和link字段是堆栈指针，但在堆栈增长期间不需要特殊的
// 处理：因为它们是指针类型的，并且
// /\临时值只存在于堆栈上，常规堆栈指针
// 调整会处理它们。
type _panic struct {
	argp      unsafe.Pointer // 指向在恐慌期间延迟调用运行的参数的指针；无法移动-已知liblink 
	arg       any            // 参数到panic 
	link      *_panic        // 链接到早期的panic 
	pc        uintptr        // 如果绕过了这个panic，在运行时返回到哪里
	sp        unsafe.Pointer // 如果绕过了这个panic，在运行时返回到哪里
	recovered bool           // 这个panic是否超过了
	aborted   bool           // 终止了这个panic 
	goexit    bool
}

// 堆栈跟踪
type stkframe struct {
	fn       funcInfo   // 正在运行的函数
	pc       uintptr    // fn内的程序计数器
	continpc uintptr    // 可以继续执行的程序计数器，或者0如果不是
	lr       uintptr    // 调用者的程序计数器aka链接寄存器
	sp       uintptr    // pc的堆栈指针
	fp       uintptr    // 调用者的堆栈指针aka帧指针
	varp     uintptr    // 局部变量的顶部
	argp     uintptr    // 函数参数的指针
	arglen   uintptr    // argp的字节数
	argmap   *bitvector // 强制使用此argmap 
}

// ancestorInfo记录goroutine开始的详细位置。wen dang
type ancestorInfo struct {
	gopc uintptr   // pc of go语句创建了这个goroutine 
}

const (
	_TraceRuntimeFrames = 1 << iota // include frames for internal runtime functions。
	_TraceTrap                      // 初始PC、SP来自陷阱，而不是来自调用的返回PC 
	_TraceJumpStack                 // 如果回溯在系统堆栈上，请在调用它的g处恢复跟踪
)

// 我们为回溯打印的最大帧数
const _TracebackMaxFrames = 100

// 等待原因解释了goroutine被停止的原因。
// 见戈帕克。不要重复使用等待原因，添加新的原因。
type waitReason uint8

const (
	waitReasonZero                  waitReason = iota // /“
	waitReasonGCAssistMarking                         // /“GC辅助标记”
	waitReasonIOWait                                  // /“IO等待”
	waitReasonChanReceiveNilChan                      // /“chan receive（nil chan）”
	waitReasonChanSendNilChan                         // /“chan send（nil chan）”
	waitReasonSelectNoCases                           // /“选择（无案例）”
	waitReasonGCAssistWait                            // /“GC辅助等待”
	waitReasonGCSweepWait                             // /“GC扫描等待”
	waitReasonGCScavengeWait                          // /“GC清除等待”
	waitReasonChanReceive                             // /“chan receive”
	waitReasonChanSend                                // /“chan send”
	waitReasonFinalizerWait                           // /“finalizer wait”
	waitReasonForceGCIdle                             // /“force GC（idle）”
	waitReasonTraceReaderBlocked                      // “trace reader（blocked）”
	waitReasonWaitForGCCycle                          // “wait for GC cycle”
	waitReasonGCWorkerIdle                            // “GC worker（idle）”
	waitReasonPreempted                               // “preempted”
	waitReasonDebugCall                               // “debug call 
)

var waitReasonStrings = [...]string{
	waitReasonZero:                  "",
	waitReasonGCAssistMarking:       "GC assist marking",
	waitReasonIOWait:                "IO wait",
	waitReasonChanReceiveNilChan:    "chan receive (nil chan)",
	waitReasonChanSendNilChan:       "chan send (nil chan)",
	waitReasonDumpingHeap:           "dumping heap",
	waitReasonGarbageCollection:     "garbage collection",
	waitReasonGarbageCollectionScan: "garbage collection scan",
	waitReasonPanicWait:             "panicwait",
	waitReasonSelect:                "select",
	waitReasonSelectNoCases:         "select (no cases)",
	waitReasonGCAssistWait:          "GC assist wait",
	waitReasonGCSweepWait:           "GC sweep wait",
	waitReasonGCScavengeWait:        "GC scavenge wait",
	waitReasonChanReceive:           "chan receive",
	waitReasonChanSend:              "chan send",
	waitReasonFinalizerWait:         "finalizer wait",
	waitReasonForceGCIdle:           "force gc (idle)",
	waitReasonSemacquire:            "semacquire",
	waitReasonSleep:                 "sleep",
	waitReasonSyncCondWait:          "sync.Cond.Wait",
	waitReasonTimerGoroutineIdle:    "timer goroutine (idle)",
	waitReasonTraceReaderBlocked:    "trace reader (blocked)",
	waitReasonWaitForGCCycle:        "wait for GC cycle",
	waitReasonGCWorkerIdle:          "GC worker (idle)",
	waitReasonPreempted:             "preempted",
	waitReasonDebugCall:             "debug call",
}

func (w waitReason) String() string {
	if w < 0 || w >= waitReason(len(waitReasonStrings)) {
		return "unknown wait reason"
	}
	return waitReasonStrings[w]
}

var (
	allm       *m
	gomaxprocs int32
	ncpu       int32
	forcegc    forcegcstate
	sched      schedt
	newprocs   int32

	// ”allpLock保护allp、idlepsmask、
	// 和timerpMask的无P读取和大小更改，以及对allp的所有写入。
	allpLock mutex
	// len（allp）=gomaxprocs；可能在安全点更改，否则
	// 不可变。
	allp []*p
	// Pidle list中Ps的位掩码，每P一位。读写必须是原子的。长度可能在安全点发生变化。
	// 
	// 每个P必须只更新自己的位。为了保持
	// 一致性，处于空闲状态的P必须与
	// 同时更新sched下的空闲P列表。锁定，否则赛车
	// pidleget可能会在pidleput设置掩码之前清除掩码，
	// 损坏位图。
	// 
	// N.B.，procresize拥有Stop the World with Sema中所有Ps的所有权。
	idlepMask pMask
	// 可能有计时器的Ps的位掩码，每P一位。读写
	// 必须是原子的。长度可能在安全点发生变化。
	timerpMask pMask

	// 一群背景工作人员。条目类型为
	// /*gcBgMarkWorkerNode。
	gcBgMarkWorkerPool lfstack

	// gcBgMarkWorker goroutines的总数。受worldsema保护。
	gcBgMarkWorkerCount int32

	// 有关可用cpu功能的信息。
	// 运行时之外的包不应使用这些
	// 因为它们不是外部api。
	// 在asm_{386，amd64}中启动时设置。s 
	processorVersionInfo uint32
	isIntel              bool

	goarm uint8 // 由cmd/link在arm系统上设置
)

// 由链接器设置，以便运行时可以确定构建模式。
var (
	islibrary bool // /-buildmode=c-共享
	isarchive bool // /-buildmode=c-存档
)

// 必须同意内部/buildcfg。实验帧指针。
const framepointer_enabled = GOARCH == "amd64" || GOARCH == "arm64"
